package droid.frame.utils.http;

import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;

import droid.frame.Config;

/**
 * @author coffee <br>
 * 2015-12-30下午12:14:55
 */
public class BitmapUtils {

    private final static String CACHE_DIR = Config.getCacheDir();

    private final static int BASE64_TYPE = Base64.NO_WRAP;

    /**
     * 图片最大宽度
     */
    private static final int IMAGE_WIDTH = 480;
    /**
     * 图片最大高度
     */
    private static final int IMAGE_HEIGHT = 800;

    /**
     * 生成的本地图片命名规则<br>
     * http://....../--/xxx.jpg 只截取最后的部分 xxx.jpg
     *
     * @param uri
     * @return
     */
    private static String getFileName(String uri) {
        if (uri == null) {
            return SystemClock.currentThreadTimeMillis() + "";
        }
        if (uri.contains("/") == false) {
            return Base64.encodeToString(uri.getBytes(), BASE64_TYPE).trim();
        }
        String name = uri.substring(uri.lastIndexOf("/") + 1);
        return Base64.encodeToString(name.getBytes(), BASE64_TYPE).trim();
    }

    /**
     * 加载网络上的Bitmap
     *
     * @param linkUrl
     * @return
     */
    public static Bitmap loadBitmapFromNet(String linkUrl) {
        return loadBitmapFromNet(linkUrl, true);
    }

    /**
     * 加载网络上的Bitmap
     *
     * @param linkUrl
     * @return
     * @isCheckLock 是否检查本地缓存
     */
    public static Bitmap loadBitmapFromNet(String linkUrl, boolean isCheckLocal) {
        if (linkUrl == null || "".equals(linkUrl.trim())) {
            return null;
        }
        Bitmap bitmap = null;
        try {
            linkUrl = linkUrl.trim();
            String fileName = getFileName(linkUrl);
            // 是否检查本地缓存
            if (isCheckLocal) {
                bitmap = loadBitmapFromLocal(fileName);
            }
            if (bitmap != null) {
                return bitmap;
            }
            bitmap = BitmapFactory.decodeStream(new URL(linkUrl).openStream());
            // 缓存图片
            cacheBitmapToFile(bitmap, fileName);
        } catch (MalformedURLException e) {
            droid.frame.utils.android.Log.w("BitmapUtils", "MalformedURLException " + e.getMessage(), null);
        } catch (FileNotFoundException e) {
            droid.frame.utils.android.Log.w("BitmapUtils", "FileNotFoundException " + e.getMessage(), null);
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        } catch (Exception e) {
            droid.frame.utils.android.Log.w("BitmapUtils", "", e);
        }
        return bitmap;
    }

    /**
     * 缓存Bitmap 写入到本地
     *
     * @param uri 为完整路径 AppConfig.getCacheDir() + "/" + System.currentTimeMillis() + ".jpg"
     */
    public static String cacheBitmapToFile(Bitmap bitmap, String uri) {
        String cacheFile = getFilePath(uri);
        if (bitmap == null || cacheFile == null) {
            return null;
        }
        try {
            File file = new File(cacheFile);
            if (file.exists() == false) {
                if (file.getParentFile().exists()) {
                    file.createNewFile();
                } else {
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                }
            }
            FileOutputStream fout = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fout);
            fout.flush();
            fout.close();
            return file.getPath();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String getFilePath(String uri) {
        String filePath = null;
        // 网络图片
        if (uri.startsWith("http://")) {
            // 返回的是一个相对路径。即文件名
            filePath = getFileName(uri);
        }
        // 本地图片 (分相对、绝对路径)
        // 传入的是文件名, 则获取完整的路径
        if (uri.startsWith("/") == false) {
            filePath = getCachePath(uri);
        } else {
            // 传入的是本地文件 绝对路径 。
            filePath = uri;
        }
        return filePath;
    }

    /**
     * 从本地读取文件
     *
     * @param uri 可以是绝对路径, 也可以是相对路径 <br>
     *            其中相对路径以{@link #CACHE_DIR}为parent目录
     */
    public static Bitmap loadBitmapFromLocal(String uri) {
        if (uri == null || uri.trim().length() == 0) {
            return null;
        }
        String filePath = getFilePath(uri);
        try {
            File file = new File(filePath);
            // 如果缓存图片存在，则返回
            if (file != null && file.exists()) {
                try {
                    // Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
                    Bitmap compressBitmap = compressBySize(file.getAbsolutePath(), IMAGE_WIDTH, IMAGE_HEIGHT);
                    return compressBitmap;
                } catch (OutOfMemoryError oom) {
                    Log.e("BitmapUtils", oom.getMessage(), oom);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据图片路径获取bitmap
     *
     * @param imagePath
     * @param width     值为0的话1：1加载
     * @param height    值为0的话1：1加载
     * @return
     */
    public static Bitmap getImageThumbnail(String imagePath, int width, int height) {
        Bitmap bitmap = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        // 获取这个图片的宽和高，注意此处的bitmap为null
        bitmap = BitmapFactory.decodeFile(imagePath, options);
        options.inJustDecodeBounds = false; // 设为 false
        // 计算缩放比
        int h = options.outHeight;
        int w = options.outWidth;
        int beWidth = 1;
        int beHeight = 1;
        if (width != 0 && height != 0) {
            beWidth = w / width;
            beHeight = h / height;
        }
        int be = 1;
        if (beWidth < beHeight) {
            be = beWidth;
        } else {
            be = beHeight;
        }
        if (be <= 0) {
            be = 1;
        }
        options.inSampleSize = be;
        // 重新读入图片，读取缩放后的bitmap，注意这次要把options.inJustDecodeBounds 设为 false
        bitmap = BitmapFactory.decodeFile(imagePath, options);
        // 利用ThumbnailUtils来创建缩略图，这里要指定要缩放哪个Bitmap对象
        if (width != 0 && height != 0)
            bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
        return bitmap;
    }

    /**
     * @param uri
     */
    public static void removeImageFromLocal(String uri) {
        if (uri == null || uri.trim().length() == 0) {
            return;
        }
        String filePath = getFilePath(uri);
        try {
            File file = new File(filePath);
            // 如果缓存图片存在，则返回
            if (file.exists()) {
                file.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param fileName
     * @return
     * @throws NullPointerException 如果sd卡不可用, 返回null此时将会抛出异常<br>
     */
    private static String getCachePath(String fileName) throws NullPointerException {
        File file = null;
        // String status = Environment.getExternalStorageState();
        // 判断是否有sdcard
        // if (status.equals(Environment.MEDIA_MOUNTED)) {
        file = new File(CACHE_DIR, fileName);
        return file.getAbsolutePath();
        // } else {
        // return null;// 没有sdcard
        // }
    }

    /**
     * bitmap转化为base64格式的字符串
     *
     * @param bitmap
     * @return
     */
    public static String base64ToStr(Bitmap bitmap) {
        String result = null;
        ByteArrayOutputStream baos = null;
        try {
            if (bitmap != null) {
                baos = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

                baos.flush();
                baos.close();

                byte[] bitmapBytes = baos.toByteArray();
                result = Base64.encodeToString(bitmapBytes, BASE64_TYPE);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (baos != null) {
                    baos.flush();
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * base64转为bitmap
     *
     * @param base64Data
     * @return
     */
    public static Bitmap base64ToBitmap(String base64Data) {
        byte[] bytes = Base64.decode(base64Data, BASE64_TYPE);
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    }

    /**
     * 把jpg文件 转化成base64
     *
     * @param imageFile 传入绝对路径
     * @return
     */
    public static String base64FromFile(String imageFile) {
        if (imageFile == null || imageFile.trim().length() == 0) {
            return null;
        }
        InputStream in = null;
        byte[] data = null;
        try {
            in = new FileInputStream(imageFile);
            data = new byte[in.available()];
            in.read(data);

            String result = Base64.encodeToString(data, BASE64_TYPE);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "";
    }

    public static boolean base64ToFile(String imgStr, String file) {
        if (imgStr == null) {
            return false;
        }
        try {
            byte[] b = Base64.decode(imgStr, BASE64_TYPE);
            for (int i = 0; i < b.length; i++) {
                if (b[i] < 0) {
                    b[i] += 256;
                }
            }
            OutputStream out = new FileOutputStream(file);
            out.write(b);
            out.flush();
            out.close();
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    public static Bitmap compressAndCropBitmap(Bitmap srcBitmap) {
        Bitmap compress = compressBySize(srcBitmap, IMAGE_WIDTH, IMAGE_HEIGHT);
        int width = compress.getWidth();
        int height = compress.getHeight();
        Bitmap result = null;
        if (width < height) {
            result = Bitmap.createBitmap(compress, 0, 0, width, width);
        } else if (width > height) {
            int left = (width - height) / 2;
            result = Bitmap.createBitmap(compress, left, 0, height, height);
        } else {
            result = compress;
        }
        return result;
    }

    public static Bitmap compressBySize(String filePath, int... widthAndHeight) {
        int width = IMAGE_WIDTH;
        int height = IMAGE_HEIGHT;
        if (widthAndHeight.length == 2) {
            width = widthAndHeight[0];
            height = widthAndHeight[1];
        }
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true; // 不去真的解析图片，只是获取图片的头部信息，包含宽高等
        // 把bitmap的信息写到 opts
        BitmapFactory.decodeFile(filePath, opts);
        // 计算图片缩放比例
        final int minSideLength = Math.min(width, height);
        opts.inSampleSize = computeSampleSize(opts, minSideLength, width * height);
        // 设置好缩放比例后，加载图片进内容；
        opts.inJustDecodeBounds = false;
        Bitmap compressedBitmap = BitmapFactory.decodeFile(filePath, opts);
        return compressedBitmap;
    }

    public static Bitmap compressBySize(Bitmap srcBitmap, int... widthAndHeight) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        srcBitmap.compress(CompressFormat.JPEG, 100, baos);
        byte[] data = baos.toByteArray();
        int width = IMAGE_WIDTH;
        int height = IMAGE_HEIGHT;
        if (widthAndHeight.length == 2) {
            width = widthAndHeight[0];
            height = widthAndHeight[1];
        }
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(data, 0, data.length, opts);
        // 计算图片缩放比例
        final int minSideLength = Math.min(width, height);
        opts.inSampleSize = computeSampleSize(opts, minSideLength, width * height);
        opts.inJustDecodeBounds = false;
        opts.inInputShareable = true;
        opts.inPurgeable = true;
        try {
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
            return bitmap;
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }
        return null;
    }

    private static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
        int roundedSize;
        if (initialSize <= 8) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }
        return roundedSize;
    }

    private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;
        int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }
        if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }

    /**
     * 图像旋转
     *
     * @param oriBmp 原始图片
     * @param degree 正值为右旋转，负值为左旋转
     * @return
     */
    public static Bitmap toRotation(Bitmap oriBmp, float degree) {
        // 创建操作图片用的matrix对象
        Matrix matrix = new Matrix();
        // 缩放图片动作
        matrix.postScale(1.0F, 1.0F);
        // 旋转图片 动作
        matrix.postRotate(degree);
        // 创建新的图片
        oriBmp = Bitmap.createBitmap(oriBmp, 0, 0, oriBmp.getWidth(), oriBmp.getHeight(), matrix, true);

        // Bitmap bitmap = Bitmap.createBitmap(oriBmp.getWidth(),
        // oriBmp.getHeight(), android.graphics.Bitmap.Config.ARGB_8888); //
        // 背景图片
        // Canvas canvas = new Canvas(bitmap); // 新建画布
        // canvas.drawBitmap(oriBmp, 0, 0, null); // 画图片
        // canvas.save(Canvas.ALL_SAVE_FLAG); // 保存画布
        // canvas.restore();
        //
        // cacheBitmapToFile(bitmap, "111");
        return oriBmp;

    }

    /**
     * 旋转图片摆正显示
     *
     * @param path bitmap源路径
     * @return 如果返回null 则说明 指定path的图片没有旋转
     */
    public static Bitmap getRotateBitmapByExif(String path) {
        try {
            ExifInterface exif = new ExifInterface(path);
            if (exif != null) { // 读取图片中相机方向信息
                int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
                int digree = 0;
                switch (ori) {
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        digree = 90;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        digree = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        digree = 270;
                        break;
                }
                if (digree != 0) {
                    Matrix m = new Matrix();
                    m.postRotate(digree);
                    Bitmap bmpSrc = BitmapFactory.decodeFile(path);
                    Bitmap newBitmap = Bitmap.createBitmap(bmpSrc, 0, 0, bmpSrc.getWidth(), bmpSrc.getHeight(), m, true);
                    return newBitmap;
                } else {
                    return null;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        bmp.compress(CompressFormat.PNG, 100, output);
        if (needRecycle) {
            bmp.recycle();
        }

        byte[] result = output.toByteArray();
        try {
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    public static Bitmap getBitmapFromPath(String path) {

        if (!new File(path).exists()) {
            System.err.println("getBitmapFromPath: file not exists");
            return null;
        }
        // Bitmap bitmap = Bitmap.createBitmap(1366, 768, Config.ARGB_8888);
        // Canvas canvas = new Canvas(bitmap);
        // Movie movie = Movie.decodeFile(path);
        // movie.draw(canvas, 0, 0);
        //
        // return bitmap;

        byte[] buf = new byte[1024 * 1024];// 1M
        Bitmap bitmap = null;

        try {
            FileInputStream fis = new FileInputStream(path);
            int len = fis.read(buf, 0, buf.length);
            bitmap = BitmapFactory.decodeByteArray(buf, 0, len);
            if (bitmap == null) {
                System.out.println("len= " + len);
                System.err
                        .println("path: " + path + "  could not be decode!!!");
            }
        } catch (Exception e) {
            e.printStackTrace();

        }

        return bitmap;
    }

    /**
     * 获取真实的路径
     * @param context
     * @param contentURI
     * @return
     */
    private String getRealPathFromURI(Context context, Uri contentURI) {
        String result;
        Cursor cursor = context.getContentResolver().query(contentURI, null, null, null, null);
        if (cursor == null) { // Source is Dropbox or other similar local file path
            result = contentURI.getPath();
        } else {
            cursor.moveToFirst();
            int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            result = cursor.getString(idx);
            cursor.close();
        }
        return result;
    }
}
